//
//  NetworkRequest.swift
//  XWClassroom
//
//  Created by xianquan on 2023/11/21.
//


import UIKit
import HandyJSON
import Alamofire

private var isDealTokenExpireing = false

private let originToken = UserDefaults.LoginModule.string(forKey: .token) ?? ""

private var loadTouristTokenCount = 0

public protocol JSONContainer {}

extension Dictionary: JSONContainer where Key == String, Value == Any {}

extension Array: JSONContainer where Element == Any {}

public enum NetworkResult<Value> {
    case success(Value)
    case failure(NSError)
}


/// T解析的类型,同时回调解析数据，不传T或传入Any则不解析，直接返回result
public struct NetworkRequest<T> {
    /// T传入Any或不传
    public static func request(networkType: NetworkType , completion: @escaping (NetworkResult<T?>) -> Void) where T == Any{
        parseData(networkType: networkType, completion: completion) { result in
            completion(.success(result))
        }
    }
    //T传入模型
    public static func request(networkType: NetworkType, completion: @escaping (NetworkResult<T?>) -> Void) where T : HandyJSON {
        parseData(networkType: networkType, completion: completion) { result in
            let data = T.self.deserialize(from: result as? Dictionary)
            //            let data = T.decode(from: result)
            completion(.success(data))
        }
    }
    /// T传入数组
    public static func request(networkType: NetworkType,  completion: @escaping (NetworkResult<T?>) -> Void) where T : ExpressibleByArrayLiteral , T.ArrayLiteralElement : HandyJSON {
        parseData(networkType: networkType, completion: completion) { result in
            let data = [T.ArrayLiteralElement].self.deserialize(from: result as? Array<Any>) as? T
            //            let data = T.decode(from: result)
            completion(.success(data))
        }
        
    }
    
    private static func parseData<N>(networkType: NetworkType , completion: @escaping (NetworkResult<N?>) -> Void , resultCallBack: @escaping (JSONContainer) ->Void) {
        let token = UserDefaults.standard.string(forKey: "token") ?? ""
        
        var headerValue: [HTTPHeader] = [/*.init(name: "token", value: token),*/
                                         .init(name: "Content-Type", value: "application/json"),
                                         .init(name: "Access-Control-Allow-Methods", value: "DELETE,PUT,POST,GET,OPTIONS"),
                                         .init(name: "Access-Control-Allow-Origin", value: "*"),
                                         .init(name: "Access-Control-Allow-Headers", value: "*")]
        if networkType.headerNeedChannelId {
            headerValue.append(.init(name: "channelId", value: "iOS"))
        }
        let url = URL(string: "\(networkType.baseUrl)\(networkType.path)")!
        let method = networkType.method
        var parameters = networkType.parameters
        if !url.absoluteString.contains("Authorization") {
            headerValue.append(.init(name: "Authorization", value: token))
        }
        if let token = parameters["token"] as? String {
            headerValue.append(.init(name: "Authorization", value: token))
            parameters.removeValue(forKey: "token")
        }
        let headers = HTTPHeaders(headerValue)
        
        
        //?token=login_app_user1166214x9wo9ghiyxeqbg128csyv1f4dxfwvllq
        
        XWLog(value: "网络请求url:\(url.absoluteString),method:\(method.rawValue),token:\(token),参数：\(parameters)")
        

        
        let completionHandler: (AFDataResponse<Data?>) -> Void = { response in
            
            switch response.result{
            case .success(let data):
                if var data = data {
                    
//                    data = str.data(using: .utf8) ?? Data()
//                    XWLog(value: "----dataStr = \(String(describing: dataStr))")
                    if let jsonToArr = try? JSONSerialization.jsonObject(with: data, options: []) as? [Any] {
                        XWLog(value: "\(url.absoluteString),网络请求返回：\(jsonToArr.descriptionByUnicode),参数：\(parameters)")
                        resultCallBack(jsonToArr)
                        return
                    }
                    do {
                        if let jsonToDic = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]{
                            var code = (jsonToDic["code"] != nil) ? jsonToDic["code"] as? Int : jsonToDic["status"] as? Int
                            if code == nil {
                                switch networkType {
                                case .getWxAccessToken:
                                    code = 1
                                default:
                                    break
                                }
                            }
                            if(code == 1 || code == 200){
                                XWLog(value: "\(url.absoluteString),网络请求返回：\(jsonToDic.descriptionByUnicode),参数：\(parameters)")
                                let result = jsonToDic["data"] ?? jsonToDic["result"]
                                let isNull = result is NSNull
                                var jsonContainer : JSONContainer? = result as? [Any]
                                if jsonContainer == nil {
                                    jsonContainer = result as? Dictionary<String,Any>
                                }
                                DispatchQueue.main.async {
                                    guard let jsonContainer = jsonContainer else {
                                        // 如果返回的data不是字典或数组，将完整数据回调回去
                                        completion(.success(jsonToDic as? N))
                                        return
                                    }
                                    if result != nil && isNull == false  {
                                        resultCallBack(jsonContainer)
                                    }
                                    else
                                    {
                                        completion(.success(nil))
                                    }
                                }
                                
                            }
                            else{
                                XWLog(value: "\(url.absoluteString),请求返回错误:\(jsonToDic.descriptionByUnicode),参数：\(parameters)")
                                DispatchQueue.main.async {
                                    if code == 401 { // 登录失效，重新登录
                                        return
                                    }
                                    completion(.failure(NSError(domain: "\(url.absoluteString)请求错误", code: code ?? 0, userInfo: jsonToDic)))
                                }
                            }
                        }
                    }
                    catch {
                        var str = String(data: data, encoding: .utf8) ?? ""
                        if str == "null" {
                            resultCallBack([])
                            return
                        }
                        str = str.replacingOccurrences(of: "\\\"", with: "\"")
                        str.removeFirst()
                        str.removeLast()
                        if let jsonToArr = try? JSONSerialization.jsonObject(with: str.data(using: .utf8) ?? Data(), options: []) as? [Any] {
                            XWLog(value: "\(url.absoluteString),网络请求返回：\(jsonToArr.descriptionByUnicode),参数：\(parameters)")
                            resultCallBack(jsonToArr)
                            return
                        }
                        else {
                            XWLog(value: "\(url.absoluteString)解析数据失败：\(error)")
                        }
                        
                    }
                }
            case .failure(let error):
                DispatchQueue.main.async {
                    completion(.failure(error as NSError))
                }
                XWLog(value: "\(url.absoluteString)网络请求错误:\(error.localizedDescription)")
            }
        }
        let timeoutInterval = 10.0
        switch networkType.dataType {
        case .raw:
            let encoding: ParameterEncoding = method == .get ? URLEncoding.default : JSONEncoding.default
            AF.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers, requestModifier: {$0.timeoutInterval = timeoutInterval}).response(completionHandler: completionHandler)
        case .query:
            AF.request(url, method: method, parameters: parameters, encoding: URLEncoding.queryString, headers: headers, requestModifier: {$0.timeoutInterval = timeoutInterval}).response(completionHandler: completionHandler)
        case .formData(let info):
            AF.upload(multipartFormData: { (formData) in
                for (key, value) in networkType.parameters {
                    if let value = value as? Data {
                        guard let info = info else { continue }
                        if info.valueKey == key {
                            formData.append(value, withName: info.name, fileName: info.fileName, mimeType: info.mimeType)
                        }
                    }
                    else {
                        formData.append("\(value)".data(using: .utf8) ?? Data(), withName: key)
                    }
                }
            }, to: url, method: method, headers: headers, requestModifier: {$0.timeoutInterval = timeoutInterval}).response(completionHandler: completionHandler)
        case .encoder:
            
            guard let arr = parameters["data"] as? [[String: Any]] else {return}
            var params: [[String: String]] = []
            if let paramsStr = arr as? [[String: String]] {
                params = paramsStr
            }
            else {
                for dic in arr {
                    var tempDic: [String: String] = [:]
                    for (key, value) in dic {
                        if let value = value as? String {
                            tempDic[key] = value
                        }
                        else {
                            tempDic[key] = "\(value)"
                        }
                    }
                    if !params.contains(tempDic){
                        params.append(tempDic)
                    }
                }
            }
            
            AF.request(url,method: method,parameters: params,encoder:JSONParameterEncoder.default, headers: headers ,requestModifier: {$0.timeoutInterval = timeoutInterval}).response(completionHandler: completionHandler)
        }
    }
    
}

public class NetwrokRequestForOC: NSObject{
    
    
    @objc public static func requestWith(type: NetworkOCType, parameters: [String: Any],completion:@escaping(Dictionary<String, Any>?, NSError?)->()) {
        let token = UserDefaults.LoginModule.string(forKey: .token) ?? ""
        let headers = HTTPHeaders([.init(name: "token", value: token),
                                   .init(name: "Content-Type", value: "application/json")])
        let url = URL(string: "\(type.baseUrl)\(type.path)")!
        let method = type.method
        XWLog(value: "网络请求url:\(url.absoluteString),method:\(method.rawValue),token:\(token),参数：\(parameters)")
        AF.request(url, method: method, parameters: parameters, headers: headers).response { response in
            
            switch response.result{
            case .success(let data):
                if let data = data {
                    if let jsonToArr = try? JSONSerialization.jsonObject(with: data, options: []) as? [Any] {
                        XWLog(value: "\(url.absoluteString)网络请求返回：\(jsonToArr.descriptionByUnicode)")
                        DispatchQueue.main.async {
                            completion(["data": jsonToArr], nil)
                        }
                    }
                    do {
                        if let jsonToDic = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]{
                            XWLog(value: "\(url.absoluteString)网络请求返回：\(jsonToDic.descriptionByUnicode)")
                            DispatchQueue.main.async {
                                completion(jsonToDic, nil)
                                let code = (jsonToDic["code"] != nil) ? jsonToDic["code"] as? Int : jsonToDic["status"] as? Int
                                if code == 401 { // 登录失效，重新登录
                                    
                                }
                            }
                        }
                    }
                    catch {
                        XWLog(value: "\(url.absoluteString)解析数据失败：\(error)")
                    }
                }
            case .failure(let error):
                DispatchQueue.main.async {
                    completion(nil,error as NSError)
                }
                XWLog(value: "\(url.absoluteString)网络请求错误:\(error)")
            }
        }
    }
    
    
}
